package yxy.game.pm2.module.passbarrier;

import org.joda.time.DateTime;
import org.redisson.api.RMap;
import yxy.apple.util.ActiveUtil;
import yxy.apple.util.RandomUtility;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.passbariestepreward;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.cherry.game.base.redis.RedisType;
import yxy.game.pm2.bean.Format;
import yxy.game.pm2.bean.PlayerBean;
import yxy.game.pm2.bean.db.dao.MySQLCacheDAO;
import yxy.game.pm2.bean.module.PlayerModule;
import yxy.game.pm2.module.battle.FighterModule;
import yxy.game.pm2.module.tower.TowerHandle;

import java.util.*;


/**
 * @author ljb
 * @descrition 斩关夺隘Module
 * @since 2022-09-05
 */
public class PassbarrierPlayerModule extends PlayerModule {

    /**
     * 难度等级规则：第一队根据战力获取难度梯度，第二队根据战力*0.8获取难度梯队  第三队*0.6
     * 隔天刷新，刷新规则后续根据初始定的难度等级进行区间随机获取
     */

    public static int overDayChallengeTimes = 10;//隔天重置的挑战次数
    public static int freeRefreshTimes = 20;//前三次免费刷新次数
    public static int refreshMinute = 1;//怪物免费的刷新时间
    public static int monsterListSize = 10;//最多存储10条
    public static int initialScore = 50;//最初50
    public static int limitScore = 50;//最多加50


    // bean===========================================================================
    private int maxScore;           //每天最高分
    private int pastMaxScore;       //历史最高分
    private int totalScore;         //当天总共的分数
    private int degree;             //当天的难度等级
    private ArrayList<Monster> monsterList = new ArrayList<Monster>();//key 怪物id  value 怪物信息
    private LinkedHashMap<String, ArrayList<Monster>> monsterLinkedHashMap = new LinkedHashMap<>();//打过的怪物列表
    private HashMap<String, Integer> passTotalMaxScore = new HashMap<String, Integer>();              //没三队的怪物  历史最高分
    private int challengePurchaseNum;//购买挑战次数
    private int lessChallengeNum;   //剩余挑战次数
    private int refreshTimes;       //刷新的次数
    private int lessFreerefreshTimes;//剩余免费刷新的次数
    private DateTime nowTime;       //更新时间（用于更新缓存）
    private DateTime updateTime;    //更新时间（用于挑战间隔）
    private DateTime refreshTime;   //用完之后需要等待一定时间恢复或消耗元宝直接刷新
    private HashMap<Integer, HeadBox> headBoxMsg = new HashMap<>();//顶部宝箱信息  key 宝箱id  value 分数
    private ArrayList<Format> formats = new ArrayList<>();// 阵容
    private int starLevelId;        //观星等级

    public HashMap<String, Integer> getPassTotalMaxScore() {
        return passTotalMaxScore;
    }

    public void setPassTotalMaxScore(HashMap<String, Integer> passTotalMaxScore) {
        this.passTotalMaxScore = passTotalMaxScore;
    }

    public int getPastMaxScore() {
        return pastMaxScore;
    }

    public void setPastMaxScore(int pastMaxScore) {
        this.pastMaxScore = pastMaxScore;
    }

    public LinkedHashMap<String, ArrayList<Monster>> getMonsterLinkedHashMap() {
        return monsterLinkedHashMap;
    }

    public void setMonsterLinkedHashMap(LinkedHashMap<String, ArrayList<Monster>> monsterLinkedHashMap) {
        this.monsterLinkedHashMap = monsterLinkedHashMap;
    }

    public int getLessFreerefreshTimes() {
        return lessFreerefreshTimes;
    }

    public void setLessFreerefreshTimes(int lessFreerefreshTimes) {
        this.lessFreerefreshTimes = lessFreerefreshTimes;
    }

    public int getStarLevelId() {
        return starLevelId;
    }

    public void setStarLevelId(int starLevelId) {
        this.starLevelId = starLevelId;
    }

    public int getMaxScore() {
        return maxScore;
    }

    public void setMaxScore(int maxScore) {
        this.maxScore = maxScore;
    }

    public int getTotalScore() {
        return totalScore;
    }

    public void setTotalScore(int totalScore) {
        this.totalScore = totalScore;
    }

    public int getDegree() {
        return degree;
    }

    public void setDegree(int degree) {
        this.degree = degree;
    }

    public ArrayList<Monster> getMonsterList() {
        return monsterList;
    }

    public void setMonsterList(ArrayList<Monster> monsterList) {
        this.monsterList = monsterList;
    }

    public int getChallengePurchaseNum() {
        return challengePurchaseNum;
    }

    public void setChallengePurchaseNum(int challengePurchaseNum) {
        this.challengePurchaseNum = challengePurchaseNum;
    }

    public int getLessChallengeNum() {
        return lessChallengeNum;
    }

    public void setLessChallengeNum(int lessChallengeNum) {
        this.lessChallengeNum = lessChallengeNum;
    }

    public int getRefreshTimes() {
        return refreshTimes;
    }

    public void setRefreshTimes(int refreshTimes) {
        this.refreshTimes = refreshTimes;
    }


    public DateTime getNowTime() {
        return nowTime;
    }

    public void setNowTime(DateTime nowTime) {
        this.nowTime = nowTime;
    }

    public DateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(DateTime updateTime) {
        this.updateTime = updateTime;
    }

    public DateTime getRefreshTime() {
        return refreshTime;
    }

    public void setRefreshTime(DateTime refreshTime) {
        this.refreshTime = refreshTime;
    }

    public HashMap<Integer, HeadBox> getHeadBoxMsg() {
        return headBoxMsg;
    }

    public void setHeadBoxMsg(HashMap<Integer, HeadBox> headBoxMsg) {
        this.headBoxMsg = headBoxMsg;
    }

    public ArrayList<Format> getFormats() {
        return formats;
    }

    public void setFormats(ArrayList<Format> formats) {
        this.formats = formats;
    }

    // func===========================================================================

    public Map<Integer, Long> getPassBarrierDegreeMap() throws RedisException {
        RMap<Integer, Long> degreeMap = RedisManager.getInstance().getConnection(RedisType.REDIS_DATA).client().getMap("INIT:passBarrierDegree");//key 难度  value 战力
        Map<Integer, Long> map = degreeMap.readAllMap();
        return map;
    }

    private static PassbarrierPlayerModule create(String playerCode) throws RedisException {
        PassbarrierPlayerModule module = new PassbarrierPlayerModule();
        module.setPlayerCode(playerCode);
        PlayerBean playerBean = PlayerBean.get(playerCode);
        long power = playerBean.getPower();
        module.setStarLevelId(0);//观星等级初始为0
        module.setPastMaxScore(0);
        //封装怪物信息
        int degree = module.getDegreeAndMonsterByPower(power);
        //设置等级
        module.setDegree(degree);
        //（最高分    总分   当天挑战次数    剩余挑战次数    刷新次数   开始结束时间   宝箱信息）重置   （更新和刷新时间不需要重置）
        module.reset();
        module.set();
        return module;
    }

    /**
     * 重置
     */
    private void reset() {
        setMaxScore(0);
        setTotalScore(0);
        setChallengePurchaseNum(0);
        setLessChallengeNum(overDayChallengeTimes);
        setRefreshTimes(0);
        setLessFreerefreshTimes(freeRefreshTimes);
        setNowTime(DateTime.now());
        setPassTotalMaxScore(new HashMap<String, Integer>());
        //设置顶部宝箱信息
        setHeadBoxMsg(getHeadBox());
        setMonsterLinkedHashMap(new LinkedHashMap<>());
    }

    /**
     * 宝箱信息
     *
     * @return
     */
    private HashMap<Integer, HeadBox> getHeadBox() {
        ArrayList<Monster> monsterList = getMonsterList();
        int totalScore = 0;
        for (Monster monster : monsterList) {
            totalScore += monster.getScore();
        }
        Map<String, passbariestepreward> allData = DataCenter.getAllData(passbariestepreward.class);
        HashMap<Integer, HeadBox> map = new HashMap<>();
        int size = 0;
        for (passbariestepreward value : allData.values()) {
            if (value.getType() != 1) continue;
            size++;
        }
        for (passbariestepreward value : allData.values()) {
            if (value.getType() != 1) continue;
            HeadBox headBox = new HeadBox();
            headBox.setId(value.getId());
            headBox.setReward(false);
            headBox.setScore(totalScore * 10 / size);
            map.put(value.getId(), headBox);
            size--;
        }
        return map;
    }

    /**
     * 根据战力保存怪物信息
     *
     * @param power
     * @return
     */
    private int getDegreeAndMonsterByPower(long power) throws RedisException {
        Map<Integer, Long> degreeMap = getPassBarrierDegreeMap();
        long degreeFirestPower = 0;//第一队怪的怪物战力
        int degreeFirest = 50;//第一队怪的怪物难度等级,默认最低难度一，50（边界）
        long degreeSecondPower = 0;//第二队怪的怪物战力
        int degreeSecond = 50;//第二队怪的怪物等级
        long degreeThridPower = 0;//第三队怪的怪物战力
        int degreeThrid = 50;//第三队怪的怪物等级

        for (Map.Entry<Integer, Long> entry : degreeMap.entrySet()) {
            int key = entry.getKey();
            long value = entry.getValue();
            //第一梯队
            if (power >= value && value > degreeFirestPower) {
                degreeFirestPower = value;
                degreeFirest = key;
            }
            //第二梯队
            if (power * 0.8 >= value && value > degreeSecondPower) {
                degreeSecondPower = value;
                degreeSecond = key;
            }
            //第三梯队
            if (power * 0.6 >= value && value > degreeThridPower) {
                degreeThridPower = value;
                degreeThrid = key;
            }
        }

        //封装怪物信息
        ArrayList<Monster> monsters = setMonster(degreeFirest, degreeSecond, degreeThrid);
        setMonsterList(monsters);
        return degreeFirest / 50 + 1;
    }


    /**
     * 根据难度算怪物信息
     */
    public void getMonsterByDegree() {
        ArrayList<Monster> monsterList = getMonsterList();
        //第一次根据战力获取梯队信息  后续根据难度获取梯队信息
        ArrayList<Monster> monsters = setMonster(monsterList.get(0).getDegree() * 50, monsterList.get(1).getDegree() * 50, monsterList.get(2).getDegree() * 50);
        setMonsterList(monsters);
    }

    /**
     * 封装3个队伍的怪物信息
     *
     * @param degreeFirest
     * @param degreeSecond
     * @param degreeThrid
     */
    private ArrayList<Monster> setMonster(int degreeFirest, int degreeSecond, int degreeThrid) {
        ArrayList<Integer> idList = getIdList(degreeFirest, degreeSecond, degreeThrid);
        ArrayList<Monster> monsterslist = new ArrayList<>();
        TowerHandle towerHandle = new TowerHandle();
        for (int i = 0; i < idList.size(); i++) {
            ArrayList<FighterModule> fighterModuleList = towerHandle.getFighterModuleList(idList.get(i));
            Integer integer = idList.get(i);
            Monster monster = new Monster();
            monster.setId(integer);
            monster.setDegree(integer / 50 + 1);
            monster.setGothrough(false);
            int score = RandomUtility.nextInt(initialScore + 10 * (integer / 50 + 1), initialScore + 10 * (integer / 50 + 1) + limitScore);
            monster.setScore(score);
            //战力计算
            long totalPower = 0l;
            for (FighterModule module : fighterModuleList) {
                totalPower += module.getTotalPower();
            }
            monster.setTotalPower(totalPower);
            monsterslist.add(monster);
        }

        return monsterslist;
    }

    //获取最高的难度
    public int getMaxDegree() throws RedisException {
        Map<Integer, Long> degreeMap = getPassBarrierDegreeMap();
        return degreeMap.size();
    }

    //获取3个队伍的怪物id
    public ArrayList<Integer> getIdList(int degreeFirest, int degreeSecond, int degreeThrid) {
        Random random = new Random();
        ArrayList<Integer> idList = new ArrayList<>();
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();
        ArrayList<Integer> list3 = new ArrayList<>();
        for (int i = (degreeFirest - 50); i < degreeFirest; i++) {
            if (i == 0) continue;
            if (i % 5 == 0) list1.add(i);
        }

        for (int i = (degreeSecond - 50); i < degreeSecond; i++) {
            if (i == 0) continue;
            if (i % 5 == 0) list2.add(i);
        }

        for (int i = (degreeThrid - 50); i < degreeThrid; i++) {
            if (i == 0) continue;
            if (i % 5 == 0) list3.add(i);
        }
        idList.add(list1.get(random.nextInt(list1.size())));
        idList.add(list2.get(random.nextInt(list2.size())));
        idList.add(list3.get(random.nextInt(list3.size())));
        return idList;
    }

    // redis==========================================================================

    private static String key(String playerCode) {
        return String.format("PLAYER:%s:MODULE:PASSBARRIER", playerCode);
    }


    public void set() {
        try {
            setv(key(getPlayerCode()), this);
        } catch (RedisException e) {
            e.printStackTrace();
        }
    }

    static public PassbarrierPlayerModule get(String playerCode) {
        try {
            PassbarrierPlayerModule module = getv(key(playerCode));

            //todo 后期放数据库
            if (module == null) {
                module = MySQLCacheDAO.getV(key(playerCode), PassbarrierPlayerModule.class);
                if (module != null) {
                    module.set();
                }//把数据同步到redis
            }

            if (module == null) {
                module = create(playerCode);
            }
            module.update();
            return module;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void update() throws RedisException {
        //隔天五点需要刷新怪物和相应缓存
        DateTime now = DateTime.now();
        int days = ActiveUtil.days(getNowTime(), now);
        DateTime dateTime = ActiveUtil.time5(now);//当天5.
        if (days >= 1 && dateTime.isBefore(now)) {
            reset();
            //根据战力重置怪物
            PlayerBean playerBean = PlayerBean.get(getPlayerCode());
            int degreeAndMonsterByPower = getDegreeAndMonsterByPower(playerBean.getPower());
            setDegree(degreeAndMonsterByPower);
            set();
        }
    }

    //存储到数据库的方法
    public static void saveToDB(String playerCode) {
        try {
            String key = key(playerCode);
            if (touchBucket(key).isExists()) {
                PassbarrierPlayerModule module = getv(key(playerCode));
                if (module != null) MySQLCacheDAO.setV(key, module);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //从redis移走数据的操作
    public static void removeAllFromRedis(String playerCode) {
        try {
            touchBucket(key(playerCode)).delete();
        } catch (RedisException e) {
            e.printStackTrace();
        }
    }

    // lock==========================================================================

    @Override
    public String lockKey() {
        return String.format("lock:%s", key(getPlayerCode()));
    }


    public static String getlockKey(String playercode) {
        return String.format("lock:%s", key(playercode));
    }

}
